#include "onu_comm.h"
#include "log.h"
#include "dial_shell/hg261gs_pppoe.h"
#include "dial_shell/pt622g_pppoe.h"

static char Svr_host[64] = "10.0.0.25", Storage_path[64] = "/tmp/wd";
static uint16_t Tcp_port = 18087, Udp_port = 17087;
static OPT_T opts[] = {
    { "-a", Svr_host, OPT_STRING, "server address." },
    { "-n", &Tcp_port, OPT_SHORT, "tcp port." },
    { "-u", &Udp_port, OPT_SHORT, "udp port." },
    { "-s", Storage_path, OPT_STRING, "storage path." },
};

extern char **environ;

static void print_env(){
    char **env = environ;

    while(*env){
        log_trace("%s", *env);
        env++;
    }
}
static int start_Probe(char* pro_name)
{
    int ret;
    char cmd[512] = {0};

    log_trace("Start Probe...");
    sprintf(cmd, "./%s -a %s -n %d -u %d --log-level trace --log-file ./onu.log --log-size 100000 &",
                pro_name, Svr_host, Tcp_port, Udp_port);
    
    ret = system(cmd);
    log_trace("%s \n ret:%d", cmd, ret);
    return ret;
}
static int _compare_cmdline(char *cmdline_file_path, char *pro_name){
    FILE *fp;
    int found = 0;
    char line[128] = {0};

    fp = fopen(cmdline_file_path, "r");
    if(!fp){
        return 0;
    }

    fgets(line, sizeof(line), fp);
    if(strstr(line, pro_name)){
        found = 1;
    }
    fclose(fp);
    return found;
}
static int _is_process_alive(char *status_file_path){
    FILE *fp;
    char line[64];
    int is_alive = 1;

    fp = fopen(status_file_path, "r");
    if(!fp){
        return 1;
    }

    while(fgets(line, sizeof(line),fp)){
        if(strstr(line, "State:")){
            if(strstr(line, "zombie") || strstr(line, "dead")){
                is_alive = 0;
            }else{
                is_alive = 1;
            }
            break;
        }
    }

    fclose(fp);
    return is_alive;
}
int check_sub_process(char* pro_name)
{
    int found = 0;
    char cmdline_file_path[256], status_file_path[256];
    DIR* proc_dir;
    struct dirent* sub_dirent;

    proc_dir = opendir("/proc");
    while ((sub_dirent = readdir(proc_dir)) != NULL) {

        if (sub_dirent->d_type == DT_DIR) {
            if (atoi(sub_dirent->d_name) > 0) {
                sprintf(cmdline_file_path, "/proc/%s/cmdline", sub_dirent->d_name);
                sprintf(status_file_path, "/proc/%s/status", sub_dirent->d_name);
                if(_compare_cmdline(cmdline_file_path, pro_name)){
                    if(_is_process_alive(status_file_path)){
                        found = 1;
                        break; 
                    }
                }
            }
        }
    }
    closedir(proc_dir);
    return found;
}
int monitor_Probe(char* pro_name)
{
    if (0 != start_Probe(pro_name))
        return 0;

    while (1) {
        sleep(3);
        if (!check_sub_process(pro_name))
            return 0;
    }
    //can not reach here.
    return 1;
}

int download_probe(comm_req_param_t* crq)
{
    int len;
    char url[512] = { 0 }, *req, version[64], down_url[512];
    cJSON* root = NULL;

    log_notice("Download Probe start.");
    root = crq2cjson(crq, root);
    cJSON_AddStringToObject(root, "clientFactory", devInfo.factory);
    req = cJSON_Print(root);
    cJSON_Delete(root);

    http_url("http", Svr_host, Tcp_port, WEB_DOWNLOAD_PROBE_PATH, url);

    if (http_download_get_url(url, req, down_url, version) == 0) {
        log_error("HTTP download get down url failed");
        free(req);
        return 0;
    }

    save_probe_version(PROBE_VERSION_FILE, version, sizeof(version));

    if ((len = http_download_file(down_url, PROBE_TAR_FILE)) == 0) {
        log_error("HTTP download Probe failed.");
        free(req);
        return 0;
    }

    if (0 != system("tar xzf " PROBE_TAR_FILE)) {
        log_syserr("Untar " PROBE_TAR_FILE " failed.");
        if (0 != system("busybox tar xzf " PROBE_TAR_FILE)) {
            log_syserr("Busybox untar " PROBE_TAR_FILE " failed.");

            log_trace("Move tar file to " ONU_PROBE_EXE);
            system("mv " PROBE_TAR_FILE " " ONU_PROBE_EXE);
            system("chmod a+x " ONU_PROBE_EXE);
        }
    }

    return 1;
}
int pre_auth(comm_req_param_t* crq)
{
    char url[1024] = { 0 };
    char* req = NULL;
    int ret = 0;
    cJSON *resp = NULL, *root = NULL, *json_ptr = NULL;

    http_url("http", Svr_host, Tcp_port, WEB_AUTH_PATH, url);

    root = crq2cjson(crq, root);
    root = devinfo2cjson(&devInfo, root);
    req = cJSON_Print(root);
    cJSON_Delete(root);

    if (!(resp = http_post(url, req))) {
        log_error("Auth:http post %s error.", url);
        goto out;
    }

    if (!cJSON_IsObject(resp)) {
        log_error("Auth:JSON Parse failed.");
        goto out;
    }

    if (!check_platform_resp(resp)) {
        goto out;
    }

    // json_ptr = cJSON_GetObjectItem(resp, "token");
    // strcpy(platform->resp.token, json_ptr->valuestring);

    json_ptr = cJSON_GetObjectItem(resp, "probeId");
    strcpy(crq->probeId, json_ptr->valuestring);

    //loader 里不要修改光猫的配置， 系统时间一般有ntp进程进行同步。
    // json_ptr = cJSON_GetObjectItem(resp, "systemTime");
    // if (json_ptr) {
    //     sys_time_update(json_ptr->valueint);
    // }

    ret = 1;
out:
    free(req);
    if (resp)
        cJSON_Delete(resp);
    return ret;
}
static int init_dir(char* storage_path)
{
    char cmd[64];

    sprintf(cmd, "rm -fr %s", storage_path);
    system(cmd);

    sprintf(cmd, "mkdir %s", storage_path);
    if (0 != system(cmd)) {
        log_syserr("Mkdir dir failed.");
        return 0;
    }
    return 1;
}
void export_dial_shell(char* storage_path)
{
    char cmd[128] = { 0 };
    char export_path[64] = { 0 };
    char* ptr = NULL;
    char* filename = NULL;
    int len = 0;
    if (is_hg261gs()) {
        ptr = hg261gs_pppoe_carray;
        filename = hg261gs_pppoe_filename;
        len = hg261gs_pppoe_len;
    } else if (is_pt622g()) {
        ptr = pt622g_pppoe_carray;
        filename = pt622g_pppoe_filename;
        len = pt622g_pppoe_len;
    } else {
        return; //do nothing
    }

    sprintf(export_path, "%s/%s", storage_path, filename);
    FILE* fp = fopen(export_path, "wb");
    int i = 0;
    for (i = 0; i < len; i++) {
        fputc(ptr[i], fp);
    }
    fclose(fp);

    sprintf(cmd, "chmod 777 %s", export_path);
    system(cmd);
}

static void subProess_in_Debug_mode(){
    char cmd[128] = {0};
    sprintf(cmd, "echo 1 > %s/wd_debug", Storage_path);
    system(cmd);
}
int main(int argc, char** argv)
{
    comm_req_param_t crq;
    uint32_t wait_sec = 1, retry_count = 0;


    if (0 > opt_parse(opts, sizeof(opts), argc, argv)) {
        return 1;
    }

    init_dir(Storage_path);
    
    log_initv(argc, argv);
    log_notice("Soft Version: %s (%s)", ONU_SW_VERSION, ONU_SW_DATE);

    if(Debug_mode()){
        subProess_in_Debug_mode();
    }

    print_env();
    
    set_sig_block();

    export_dial_shell(Storage_path);

    chdir(Storage_path);

    memset(&devInfo, 0, sizeof(DevInfo_t));

    if(is_TEWA500AG()){
        if(Debug_mode() == 0){
            log_trace("sleep 10 min");
            sleep(600);
        }
    }

    // log_trace("check dev if is bridge mode.");
    // if(devinfo_is_bridge()){
    //     log_trace("dev is bridge mode.");
    //     if(devinfo_has_internet_r()){
    //         log_trace("dev has internet route mode.");
    //         char pppoe_usr[64] ={0}, pppoe_pwd[64] = {0};
    //         int _ret = devinfo_get_internet_r_usr_pwd(pppoe_usr, pppoe_pwd);
    //         log_trace("usr:%s, pwd:%s", pppoe_usr, pppoe_pwd);
    //         if(_ret){
    //             log_trace("dev del pppoe %s %s", pppoe_usr, pppoe_pwd);
    //             devinfo_del_pppoe_dial(pppoe_usr, pppoe_pwd);
    //             sleep(10);
    //         }
    //     }else{
    //         log_trace("dev not has internet route mode.");
    //     }
    // }else{
    //     log_trace("dev is Router mode.");
    // }

    log_trace("...");

Get_gateway_interface:

    //友华光猫在启动后不能立即添加网络连接成功，需多尝试几次
    if(devinfo_has_internet_r() == 0){
        log_trace("dev has no internet route mode, add "PRE_PPPOE_USER" "PRE_PPPOE_PWD);
        devinfo_add_pppoe_dial(PRE_PPPOE_USER, PRE_PPPOE_PWD);
    }else{
        log_trace("dev has internet route mode.");
    }

    if (!check_gateway_interface(devInfo.ifname)) {
        log_warn("Can not get gateway interface, retry...");
        log_trace("retry_count:%d", retry_count);
        if(retry_count == 5){
            if(devinfo_is_bridge()){
                log_trace("dev is bridge mode.");
                if(devinfo_has_internet_r()){
                    log_trace("dev has internet route mode.");
                    char pppoe_usr[64] ={0}, pppoe_pwd[64] = {0};
                    int _ret = devinfo_get_internet_r_usr_pwd(pppoe_usr, pppoe_pwd);
                    log_trace("usr:%s, pwd:%s", pppoe_usr, pppoe_pwd);

                    if(_ret){
                        if(strcmp(pppoe_usr, PRE_PPPOE_USER) != 0){//非预置账号，则在上面会换成预置账号
                            log_trace("dev del pppoe %s %s", pppoe_usr, pppoe_pwd);
                            devinfo_del_pppoe_dial(pppoe_usr, pppoe_pwd);
                        }   
                    }
                }else{
                    log_trace("dev not has internet route mode.");
                }
            }else{
                log_trace("dev is Router mode.");
            }
        }
        retry_count++;
        sleep(60);
        goto Get_gateway_interface;
    }

    //loader 需要在连到网络后，才解析平台域名
    if(!server_addr_to_ipstr(Svr_host)){
        sleep(1);
        goto Get_gateway_interface;
    }

    load_devinfo(&devInfo);

    init_comm_req_param(&crq, &devInfo);

retry:
    wait_sec = _cal_wait_sec(wait_sec);
    if (!pre_auth(&crq)) {
        log_warn("Auth Probe failed, wait %d sec.", wait_sec);
        sleep(wait_sec);
        goto retry;
    }

    if (!download_probe(&crq)) {
        log_warn("Download Probe failed, wait %d sec.", wait_sec);
        sleep(wait_sec);
        goto retry;
    }

    if (!monitor_Probe(ONU_PROBE_EXE)) {
        sleep(wait_sec);
        goto retry;
    }
    return 1;
}
